package com.cskaoyan.javse.oop3._2inner._7lambda._0introduction;

/**
 * @description: lambda表达式的引入
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * > 仅做参考与了解：lambda表达式
 * > Lambda 表达式是 JDK8 的一个新特性，可以取代接口的匿名内部类，写出更优雅的 Java 代码
 * > 匿名内部类实际上是局部内部类的更进一步，简化了局部内部类
 * > 那么lambda就是匿名内部类更进一步，语法上更简洁了，代码更优雅了，是高端的玩法
 * > 是人上人的玩法
 *
 * 从上面描述可以得出:
 *      1.lambda表达式仍然是局部内部类,是特殊的局部内部类.仍然定义在局部位置(方法中)
 *      2.lambda表达式在取代匿名内部类时,不是全部都取代,而是取代接口的匿名内部类,而类的匿名内部类
 *          lambda表达式是不能取代的
 *      3.lambda表达式是匿名内部类的更进一步,lambda表达式得到的也不是一个类,也是一个对象,并且是接口的子类对象
 *
 * lambda表达式的使用:
 *      1.前提:
 *          使用lambda表达式取代接口的匿名内部类,不是所有接口都可以的,
 *          lambda表达式要求的接口必须有且仅有一个必须要实现的抽象方法
 *          这种接口在java中称之为"功能接口"
 *          功能接口在语法上可以使用注解@FunctionalInterface检测它,
 *          功能接口用它标记后不会报错,反之会编译报错
 *          思考两个问题:
 *              a.功能接口中只能有一个方法吗?
 *                  不是,Java8中的默认方法和静态方法不需要子类实现,功能接口中可以允许有它们存在
 *              b.功能接口中只能有一个抽象方法吗?
 *                  不是,有些抽象方法在子类实现接口时不需要去实现
 *                  什么样的抽象方法,不需要实现类实现?
 *                      在java中,任何类都会继承Object,那么如果抽象方法是Object类当中已经存在实现的方法,那么就无须实现类去实现它,而是可以直接将Object类方法作为实现
 *
 *      2.功能接口准备完毕后,就可以写lambda表达式的语法了:
 *          () -> {
 *              //方法体
 *          }
 *          解释一下:
 *          () 表示功能接口中要重写的抽象方法的形参列表
 *          -> 它是lambda表达式运算符,读作"goes to"
 *          {
 *              //方法体
 *          }
 *          表示功能接口中要重写的抽象方法重写的方法体
 *
 *         为什么lambda表达式要求接口必须只有一个要实现的抽象方法?
 *         因为语法中仅有一套形参列表和方法体,只能重写一个方法
 *         并且lambda表达式只能重写父接口中的抽象方法,是不能自己新增成员的
 *
 *    3.直接在方法中写lambda表达式的语法,肯定是会报错的,原因在于java是强类型语言,任何变量都有它的数据类型,而直接写lambda表达式语言,编译器是无从得知它的数据类型的.
 *    所以我们需要帮助编译器,明确lambda表示所表示的对象的类型,这个过程称之为"lambda表达式的类型推断"
 *    在这个推断过程中,需要给编译器提供额外的信息,让编译器能够知道lambda表达式表示对象的类型,总的来说,常见的有四种方式:
 *     a.直接用父接口引用接收
 *          由于lambda表达式表示的子类对象并没有自己独有的成员,所以直接用父类引用接收
 *     b.不用引用接收,但是要直接告诉编译器lambda表达式的类型
 *     语法: (父接口的名字)lambda表达式
 *     但是这种方式需要直接使用该子类对象调用方法
 *     c.借助方法完成类型推断
 *          可以借助方法的返回值完成类型推断
 *          可以解除方法的形参的数据类型完成类型推荐
 *
 * 以上lambda表达式最最基础使用,就完成了
 *
 */
public class Demo {
    public static void main(String[] args) {

        //创建IA的子类对象,用匿名内部类
        new IA() {
            @Override
            public void method() {
                System.out.println("hello world!");
            }
        }.method();

        //创建IA的子类对象,用lambda表达式
        IA ia = () -> {
            System.out.println("我是仌");
        };
        ia.method();

        ((IB) () -> {
            System.out.println("我是方式二");
        }).method();

        test().method();

        test(() -> {
            System.out.println("我借助方法的形参数据类型完成类型推断");
        });

        test(() -> System.out.println("hello"));
        test(System.out::println);
        System.out.println("=========");

    }

    public static IA test() {
        return () -> {
            System.out.println("我借助方法的返回值类型完成类型推断");
        };
    }

    public static void test(IB ib) {
        ib.method();
    }
}

@FunctionalInterface
interface IA {
    void method();
    //void method2();
    //boolean equals(Object obj);

    /*//默认方法
    default void test(){}
    //静态方法
    static void testStatic(){}*/
}

@FunctionalInterface
interface IB {
    void method();
}